/*
 * @ (#) CmppDeliverPacket.java Jun 8, 2008
 *
 * 
 */
package com.aspire.nm.component.cmppserver.filter.coder.packet;

import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.Date;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;

import com.aspire.nm.component.commonUtil.bytes.BytesUtil;

/**
 * CMPP_DELIVER
 *
 * <p>
 * 参照：中国移动通信互联网短信网关接口协议CMPP3.0, 中国移动通信互联网短信网关接口协议CMPP2.0
 * </p>
 *
 * @author	Wang Shenggong
 * @version 1.0.0
 * @since 1.0.0
 *
 */
public class CmppDeliverPacket extends CmppPacket {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	// Message is delivered to destination
	public static String STAT_DELIVERED = "DELIVRD";
	
	// Message validity period has expired
	public static String STAT_EXPIRED = "EXPIRED";
	
	// Message has been deleted.
	public static String STAT_DELETED = "DELETED";
	
	// Message is undeliverable
	public static String STAT_UNDELIVERABLE = "UNDELIV";
	
	// Message is in accepted state(i.e. has been manually read on behalf of the subscriber by customer service)
	public static String STAT_ACCEPTED = "ACCEPTD";
	
	// Message is in invalid state
	public static String STAT_UNKNOWN = "UNKNOWN";
	
	// Message is in a rejected state
	public static String STAT_REJECTED = "REJECTED";
	
	// SMSC不返回响应消息时的状态报告
	public static String STAT_MA = "MA:xxxx";
	
	// SMSC返回错误响应消息时的状态报告
	public static String STAT_MB = "MB:xxxx";
	
	// SCP不返回响应消息时的状态报告
	public static String STAT_CA = "CA:xxxx";
	
	// SCP返回错误响应消息时的状态报告
	public static String STAT_CB = "CB:xxxx";
	
	/**
	 * 非状态报告 Registered_Delivery=0
	 */
	public static byte REGISTERED_DELIVERY_NO = 0x00;
	
	/**
	 * 状态报告 Registered_Delivery=1
	 */
	public static byte REGISTERED_DELIVERY_YES = 0x01;
	
	/**
	 * 上行短信
	 */
	public final static byte MSG_TYPE_SMS_MO = 0;
	
	/**
	 * 下行短信状态报告
	 */
	public final static byte MSG_TYPE_SMS_STAT_REPORT = 1;
	
	/**
	 * WAP PUSH状态报告
	 */
	public final static byte MSG_TYPE_PUSH_STAT_REPORT = 2;
	
	// 信息标识
	private long msgId;
	
	// 目的号码
	private String destId;
	
	// 业务标识
	private String serviceId;
	
	// GSM协议类型
	private byte tpPid;
	
	// GSM协议类型
	private byte tpUdhi;
	
	// 消息格式: 0: ASCII;3:短信写卡操作;4:二进制信息;8:UCS2编码;15:含GB汉字
	private byte msgFmt;
	
	// 源终端MSISDN号码, 状态报告时填为CMPP_SUBMIT消息的目的终端号码
	private String srcTerminalId;
	
	// 源终端类型, 0:真实号码; 1:伪码
	private byte srcTerminalType;
	
	// 是否为状态报告
	private byte registeredDelivery;
	
	// 消息长度
	private int msgLength;
	
	// 消息内容
	private byte[] msgContent;
	
	// 点播业务使用的LinkID，非点播类业务的MT流程不使用该字段
	private String linkId;
	
	// -- 如果为状态报告, 一下信息有效 -----------------------------------------------------
	
	// 消息标识
	// SP提交短信（CMPP_SUBMIT）操作时，与SP相连的ISMG产生的Msg_Id
	private long ismgMsgId;
	
	// 发送短信的应答结果，含义与SMPP协议要求中stat字段定义相同，详见表一。
	// SP根据该字段确定CMPP_SUBMIT消息的处理状态。
	private String stat;
	
	// Submit_time
	private String submitTime;
	
	// Done_time
	private String doneTime;
	
	// 目的终端MSISDN号码(SP发送CMPP_SUBMIT消息的目标终端)
	private String destTerminalId;
	
	// 取自SMSC发送状态报告的消息体中的消息标识。
	private int smscSequence;
	// ------------------------------------------------------------------------
	
	
	
	
	
	public CmppDeliverPacket(){
		commandId = CmppPacket.CMPP_DELIVER;
	}
	
	public CmppDeliverPacket(Version version){
		super(version);
		commandId = CmppPacket.CMPP_DELIVER;
	}
	
	
	public byte[] pack()  throws PacketException{
		
		if(!this.isRegisteredDelivery() && msgContent == null)
			msgContent = new byte[]{'\0'};
		
		// 计算包长度
		int mainLength = version.isVersion3() ? 97 : 73;
		
		int reportLength = 60;
		
		// 如果为状态报告, 消息内容长度将改为60
		msgLength = isRegisteredDelivery() ? reportLength : msgContent.length;		
		
		//wxn 2014-09-16 长短信的情况，内容长度增加
		if( this.isLongSMS() )
		{
			msgLength += this.longFlagSize;
		}
		//wxn end
		
		totalLength = HEADER_LENGTH + mainLength + msgLength;
		
		// 打包包头
		super.pack();
		
		try {
			putLong(msgId);
			putStringRightPad(destId, 21);
			putStringRightPad(serviceId, 10);
			put(tpPid);
			put(tpUdhi);
			put(msgFmt);
			putStringRightPad(srcTerminalId, version.isVersion3() ? 32 : 21);
			if(version.isVersion3()) put(srcTerminalType);
			put(registeredDelivery);
			put((byte)msgLength);
			
			// 如果为状态报告, 现有msgContent内容将无效, 根据状态报告字段内容打包状态报告消息内容
			
			if(isRegisteredDelivery()){
				putLong(ismgMsgId);
				putStringRightPad(stat, 7);
				putStringRightPad(submitTime, 10);
				putStringRightPad(doneTime, 10);
				putStringRightPad(destTerminalId, 21);
				putInt(smscSequence);
			}else{
				
				//wxn 2014-09-16 长短信的情况，在短信内容前增加长短信相关信息
				if( this.isLongSMS() )
				{
					this.put(this.longFlagByteArray);
				}
				//wxn end
				
				put(msgContent);
			}
			
			if (null != linkId && linkId.getBytes().length > 20)
				linkId = null;
			putStringRightPad(linkId, version.isVersion3() ? 20 : 8);
		} catch (Exception e) {
			throw new PacketException("Unexpected Exception on packing CmppDeliverPacket: TotalLength=" + totalLength + ", CommandId=" + Integer.toHexString(commandId) + ", SequenceId=" + sequenceId+", linkId="+linkId, e);			
		}
		return getBytes();
		
	}

	
	
	public CmppPacket unpack(ByteBuffer buffer) throws PacketException{
		
		super.unpack(buffer);
		
		try {
			msgId = getLong();
			destId = getString(21);
			serviceId = getString(10);
			tpPid = get();
			tpUdhi = get();
			msgFmt = get();
			srcTerminalId = getString(version.isVersion3() ? 32 : 21);
			if(version.isVersion3()) srcTerminalType = get();
			registeredDelivery = get();
			msgLength = get();
			
			// 如果Registered_Delivery为1
			if(isRegisteredDelivery()){
				
				ismgMsgId = getLong();
				stat = getString(7);
				submitTime = getString(10);
				doneTime = getString(10);
				destTerminalId = getString(21);
				smscSequence = getInt();
				
			}else{
				msgContent = new byte[msgLength];
				get(msgContent);
			}
			
			linkId = getString(version.isVersion3() ? 20 : 8);
		} catch (Exception e) {
			throw new PacketException("Unexpected Exception on unpacking CmppDeliverPacket: TotalLength=" + totalLength + ", CommandId=" + Integer.toHexString(commandId) + ", SequenceId=" + sequenceId, e);
		}
		
		return this;
	}

	/**
	 * @return the msgId
	 */
	public long getMsgId() {
		return msgId;
	}

	/**
	 * @param msgId the msgId to set
	 */
	public void setMsgId(long msgId) {
		this.msgId = msgId;
	}

	/**
	 * @return the destId
	 */
	public String getDestId() {
		return destId;
	}

	/**
	 * @param destId the destId to set
	 */
	public void setDestId(String destId) {
		this.destId = destId;
	}

	/**
	 * @return the serviceId
	 */
	public String getServiceId() {
		return serviceId;
	}

	/**
	 * @param serviceId the serviceId to set
	 */
	public void setServiceId(String serviceId) {
		this.serviceId = serviceId;
	}

	/**
	 * @return the tpPid
	 */
	public byte getTpPid() {
		return tpPid;
	}

	/**
	 * @param tpPid the tpPid to set
	 */
	public void setTpPid(byte tpPid) {
		this.tpPid = tpPid;
	}

	/**
	 * @return the tpUdhi
	 */
	public byte getTpUdhi() {
		return tpUdhi;
	}

	/**
	 * @param tpUdhi the tpUdhi to set
	 */
	public void setTpUdhi(byte tpUdhi) {
		this.tpUdhi = tpUdhi;
	}

	/**
	 * @return the msgFmt
	 */
	public byte getMsgFmt() {
		return msgFmt;
	}

	/**
	 * @param msgFmt the msgFmt to set
	 */
	public void setMsgFmt(byte msgFmt) {
		this.msgFmt = msgFmt;
	}

	/**
	 * @return the srcTerminalId
	 */
	public String getSrcTerminalId() {
		return srcTerminalId;
	}

	/**
	 * @param srcTerminalId the srcTerminalId to set
	 */
	public void setSrcTerminalId(String srcTerminalId) {
		this.srcTerminalId = srcTerminalId;
	}

	/**
	 * @return the srcTerminalType
	 */
	public byte getSrcTerminalType() {
		return srcTerminalType;
	}

	/**
	 * @param srcTerminalType the srcTerminalType to set
	 */
	public void setSrcTerminalType(byte srcTerminalType) {
		this.srcTerminalType = srcTerminalType;
	}

	/**
	 * @return the registeredDelivery
	 */
	public byte getRegisteredDelivery() {
		return registeredDelivery;
	}

	/**
	 * @param isRegisteredDelivery the registeredDelivery to set
	 */
	public void setRegisteredDelivery(boolean isRegisteredDelivery) {
		this.registeredDelivery = isRegisteredDelivery ?  REGISTERED_DELIVERY_YES : REGISTERED_DELIVERY_NO;
	}

	/**
	 * @return the msgLength
	 */
	public int getMsgLength() {
		return msgLength;
	}

	/**
	 * @param msgLength the msgLength to set
	 */
	
	public void setMsgLength(int msgLenght) {
		this.msgLength = msgLenght;
	}
	
	
	/**
	 * @return the msgContent
	 */
	public byte[] getMsgContent() {
		return msgContent;
	}

	/**
	 * @param msgContent the msgContent to set
	 */
	public void setMsgContent(byte[] msgContent) {
		this.msgContent = msgContent;
	}

	/**
	 * @return the linkId
	 */
	public String getLinkId() {
		return linkId;
	}

	public String getReserved(){
		return linkId;
	}
	
	/**
	 * @param linkId the linkId to set
	 * @throws UnsupportedEncodingException 
	 */
	public void setLinkId(String linkId) throws UnsupportedEncodingException {
		//this.linkId = linkId;		
		setLinkidORReserved(linkId);
		
		//如果是长短信，修改编码
		if( this.isLongSMS() && ArrayUtils.isNotEmpty(this.msgContent) )
		{
			String msg = new String(msgContent, "GBK");
			msgContent = msg.getBytes("UTF-16BE");
		}
	}
	
	public void setReserved(String reserved){		

		//wxn 2014-09-16 长短信的情况，内容长度增加
		setLinkidORReserved(reserved);
	}
	
	
	/**
	 * 由于以前的逻辑都设置linkid，所以提炼到这里，兼容长短信
	 * @param str
	 */
	private void setLinkidORReserved( String str )
	{
		//wxn 2014-09-16 长短信的情况，内容长度增加
		if( StringUtils.contains(str, "#") )
		{
			this.longFlag = StringUtils.substringBefore(str, "#");
			this.linkId = StringUtils.substringAfter(str, "#");
			
			if( StringUtils.isNotBlank(longFlag) )
			{
				
				this.longFlagByteArray = BytesUtil.hex2bytes(this.longFlag);
				this.longFlagSize = ArrayUtils.getLength(this.longFlagByteArray);
			}
			
			if( this.isLongSMS() )
			{
				//长短信标志位
				this.msgFmt = 8;
				this.tpUdhi = 1;
			}
		}		
		//wxn end
		else
		{
			this.linkId = str;
		}
	}
	
	//2014-09-16 自定义长短信标识字段
	private String longFlag = "";//传入的字符串
	private byte[] longFlagByteArray = null;//转码为字节数组
	private int longFlagSize = 0;//字节数组的尺寸，6或7是长短信
	
	/**
	 * @return the iSMGMsgId
	 */
	public long getIsmgMsgId() {
		return ismgMsgId;
	}

	/**
	 * @param msgId the iSMGMsgId to set
	 */
	public void setIsmgMsgId(long msgId) {
		ismgMsgId = msgId;
	}

	/**
	 * @return the stat
	 */
	public String getStat() {
		return stat;
	}

	/**
	 * @param stat the stat to set
	 */
	public void setStat(String stat) {
		this.stat = stat;
	}

	/**
	 * @return the submitTime
	 */
	public String getSubmitTime() {
		return submitTime;
	}

	/**
	 * @param submitTime the submitTime to set
	 */
	public void setSubmitTime(String submitTime) {
		this.submitTime = submitTime;
	}

	/**
	 * @return the doneTime
	 */
	public String getDoneTime() {
		return doneTime;
	}

	/**
	 * @param doneTime the doneTime to set
	 */
	public void setDoneTime(String doneTime) {
		this.doneTime = doneTime;
	}

	/**
	 * @return the destTerminalId
	 */
	public String getDestTerminalId() {
		return destTerminalId;
	}

	/**
	 * @param destTerminalId the destTerminalId to set
	 */
	public void setDestTerminalId(String destTerminalId) {
		this.destTerminalId = destTerminalId;
	}

	/**
	 * @return the smscSequence
	 */
	public int getSmscSequence() {
		return smscSequence;
	}

	/**
	 * @param smscSequence the smscSequence to set
	 */
	public void setSmscSequence(int smscSequence) {
		this.smscSequence = smscSequence;
	}
	
	/**
	 * 
	 * @return
	 */
	public boolean isRegisteredDelivery(){
		return registeredDelivery == REGISTERED_DELIVERY_YES ? true : false;
	}
	
	/**
	 * @param date
	 */
	public void setSubmitTime(Date date){
		if(date == null) return;
		//SimpleDateFormat df = new SimpleDateFormat("yyMMddHHmm");		
		//submitTime = df.format(date);
		submitTime = DateFormatUtils.format(date, "yyMMddHHmm");
	}
	
	/**
	 * @param date
	 */
	public void setDoneTime(Date date){
		if(date == null) return;
		//SimpleDateFormat df = new SimpleDateFormat("yyMMddHHmm");
		
		//doneTime = df.format(date);
		doneTime = DateFormatUtils.format(date, "yyMMddHHmm");
	}
	
	/**
	 * 判断消息类型是否为普通上行短信
	 * @return
	 */
	public boolean isSMSMO(){
		return MSG_TYPE_SMS_MO == registeredDelivery;
	}
	
	/**
	 * 判断消息类型是否为下行短信状态报告
	 * @return
	 */
	public boolean isSMSReport(){
		return MSG_TYPE_SMS_STAT_REPORT == registeredDelivery;
	}
	
	/**
	 * 判断消息类型是否为WAP PUSH状态报告
	 * @return
	 */
	public boolean isPushReport(){
		return MSG_TYPE_PUSH_STAT_REPORT == registeredDelivery;
	}
	
	public void setRegisteredDelivery(byte registeredDelivery){
		this.registeredDelivery = registeredDelivery;
	}
	
	/**
	 * 返回根据Msg_Fmt解码的字符串消息
	 * 
	 * @return
	 */
	public String getMsgContentDecoded(){
		String ret = null;
		
		if(isRegisteredDelivery()) return ret;
		
		try{
			switch(msgFmt){
				case 0: ret = new String(msgContent, "US-ASCII");break;
				case 4: ret = BytesUtil.bytes2hex(msgContent);break;
				case 8: ret = new String(msgContent, "UTF-16BE");break;
				case 15: ret = new String(msgContent, "GBK");break;
				default : ret = new String(msgContent);
			}
		}catch(UnsupportedEncodingException e){
			ret = new String(msgContent);
		}
		
		return ret;
	}
	
	public String toString(){
		StringBuffer sb = new StringBuffer();
		
		if(isRegisteredDelivery())
			sb.append("[Report]CMPP_DELIVER:");
		else
			sb.append("CMPP_DELIVER:");
		
		sb.append("Sequence_Id=").append(sequenceId);
		sb.append(", Msg_Id=").append(msgId);
		
		if(isRegisteredDelivery()){
			sb.append(", IMSG_Msg_Id=").append(ismgMsgId);
			sb.append(", Stat=").append(stat);
			sb.append(", Submit_time=").append(submitTime);
			sb.append(", Done_time=").append(doneTime);
			sb.append(", Dest_terminal_Id=").append(destTerminalId);
			sb.append(", SMSC_sequence=").append(smscSequence);
			
		}else{
			sb.append(", Dest_Id=").append(destId);
			sb.append(", Service_Id=").append(serviceId);
			sb.append(", TP_pid=").append(tpPid);
			sb.append(", TP_udhi=").append(tpUdhi);
			sb.append(", Msg_Fmt=").append(msgFmt);
			sb.append(", Src_terminal_Id=").append(srcTerminalId);
			sb.append(", Src_terminal_type=").append(srcTerminalType);
			sb.append(", Registered_Delivery=").append(registeredDelivery);
			sb.append(", Msg_Length=").append(msgLength);
			//
			sb.append(", Msg_Content=").append(getMsgContentDecoded());
			sb.append(", LinkID=").append(linkId);
			
			if( this.isLongSMS() )
			{
				sb.append(", LongFlag=").append(this.longFlag);
			}
		}
		sb.append(", resend =").append(this.bizParams);
		return sb.toString();
	}
	
	
	private boolean isLongSMS()
	{
		if( this.longFlagSize == 6 || this.longFlagSize == 7 )
		{
			return true;
		}
		else
		{
			return false;
		}		
	}
}
